package it.uniroma2.art.coda.main;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Set;

import it.uniroma2.art.owlart.exceptions.ModelAccessException;
import it.uniroma2.art.owlart.exceptions.ModelCreationException;
import it.uniroma2.art.owlart.exceptions.ModelUpdateException;
import it.uniroma2.art.owlart.exceptions.QueryEvaluationException;
import it.uniroma2.art.owlart.exceptions.UnsupportedQueryLanguageException;
import it.uniroma2.art.owlart.exceptions.UnsupportedRDFFormatException;
import it.uniroma2.art.owlart.io.RDFFormat;
import it.uniroma2.art.owlart.model.ARTNode;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.model.NodeFilters;
import it.uniroma2.art.owlart.models.OWLArtModelFactory;
import it.uniroma2.art.owlart.models.OWLModel;
import it.uniroma2.art.owlart.models.UnloadableModelConfigurationException;
import it.uniroma2.art.owlart.models.UnsupportedModelConfigurationException;
import it.uniroma2.art.owlart.models.conf.ModelConfiguration;
import it.uniroma2.art.owlart.query.MalformedQueryException;
import it.uniroma2.art.owlart.query.Query;
import it.uniroma2.art.owlart.query.TupleBindings;
import it.uniroma2.art.owlart.query.TupleBindingsIterator;
import it.uniroma2.art.owlart.query.TupleQuery;
import it.uniroma2.art.owlart.sesame2impl.factory.ARTModelFactorySesame2Impl;

public class SPARQLTest {


	// private static String txtFilePath = "E:/CODATest/test.txt";
	// private static String htmlFilePath = "E:/CODATest/andreaRedux.html";

	private String baseUri = "http://art.uniroma2.it";
	// private static String importedUri = "http://viaggio";
	private String importedUri = "http://PersonEmail";

	// private static String rdfInputFilePath = "E:/CODATest/rdfFile.owl";
	// private String rdfInputFilePath = "E:/CODATest/PersonEmail.owl";
	private String rdfInputFilePath = "E:/CODATest/Publication.owl";
	private String rdfOutputFilePath = "E:/CODATest/SPARQLTest.owl";

	private String repositoryDirPath = "E:/CODATest/repDir";
	
	private static boolean verbose = true;

	public static void main(String[] args) {
		System.out.println("program started");
		SPARQLTest sparqlTest = new SPARQLTest();
		OWLModel owlModel = null;

		try {
			owlModel = sparqlTest.initializeRDFModel();
			
			sparqlTest.popolateOWLModel(owlModel);
			
			TupleBindingsIterator tupleBindIter = sparqlTest.executeQuery(owlModel);
			
			sparqlTest.printQueryResult(tupleBindIter);
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (ModelUpdateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ModelAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedRDFFormatException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (ModelCreationException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedModelConfigurationException e) {
			e.printStackTrace();
		} catch (UnloadableModelConfigurationException e) {
			e.printStackTrace();
		} catch (UnsupportedQueryLanguageException e) {
			e.printStackTrace();
		} catch (MalformedQueryException e) {
			e.printStackTrace();
		} catch (QueryEvaluationException e) {
			e.printStackTrace();
		}finally{
			try {
				System.out.println("program terminated");
				owlModel.close();
			} catch (ModelUpdateException e) {
				e.printStackTrace();
			}
		}
		
	}


	private OWLModel initializeRDFModel() throws ModelUpdateException, FileNotFoundException, IOException,
			ModelAccessException, UnsupportedRDFFormatException, ClassNotFoundException,
			ModelCreationException, InstantiationException, IllegalAccessException,
			UnsupportedModelConfigurationException, UnloadableModelConfigurationException {

		/*
		 * String owlArtModelFactoryImplClassName =
		 * "it.uniroma2.art.owlart.sesame2impl.factory.ARTModelFactorySesame2Impl"; Class<? extends
		 * ModelFactory> owlArtModelFactoryImplClass = (Class<? extends ModelFactory>)
		 * Class.forName(owlArtModelFactoryImplClassName); OWLArtModelFactory artModelFact =
		 * OWLArtModelFactory.createModelFactory( owlArtModelFactoryImplClass.newInstance());
		 */
		OWLArtModelFactory artModelFact = OWLArtModelFactory
				.createModelFactory(new ARTModelFactorySesame2Impl());
		String mcClassName = "it.uniroma2.art.owlart.sesame2impl.models.conf.Sesame2PersistentInMemoryModelConfiguration";
		Class mcClass = Class.forName(mcClassName);
		ModelConfiguration modelConf = artModelFact.createModelConfigurationObject(mcClass);
		OWLModel owlModel = artModelFact.loadOWLModel(baseUri, repositoryDirPath, modelConf);
		owlModel.setBaseURI(baseUri);
		owlModel.setDefaultNamespace(baseUri + "#");
		owlModel.clearRDF();
		owlModel.addRDF(new File(rdfInputFilePath), importedUri, RDFFormat.RDFXML, NodeFilters.MAINGRAPH);

		return owlModel;
	}
	
	private void popolateOWLModel(OWLModel owlModel) throws ModelUpdateException {
		String personClassString = owlModel.getDefaultNamespace()+"Person";
		ARTURIResource personClassRes = owlModel.createURIResource(personClassString);
		
		String andreaInstString = owlModel.getDefaultNamespace()+"Andrea";
		ARTURIResource andreaInstRes = owlModel.createURIResource(andreaInstString);
		String noemiInstString = owlModel.getDefaultNamespace()+"Noemi";
		ARTURIResource noemiInstRes = owlModel.createURIResource(noemiInstString);
		String armandoInstString = owlModel.getDefaultNamespace()+"Armando";
		ARTURIResource armandoInstRes = owlModel.createURIResource(armandoInstString);
		
		String turbatiString = "Turbati";
		ARTNode turbatiRes = owlModel.createLiteral(turbatiString);
		
		
		String conoscePropString = owlModel.getDefaultNamespace()+"conosce";
		ARTURIResource conoscePropRes = owlModel.createURIResource(conoscePropString);
		
		String cognomePropString = owlModel.getDefaultNamespace()+"cognome";
		ARTURIResource cognomePropRes = owlModel.createURIResource(cognomePropString);
		
		
		owlModel.addClass(personClassString);
		owlModel.addInstance(andreaInstString, personClassRes);
		owlModel.addInstance(noemiInstString, personClassRes);
		owlModel.addInstance(armandoInstString, personClassRes);
		
		owlModel.addObjectProperty(conoscePropString, null);
		owlModel.addDatatypeProperty(cognomePropString, null);
		
		owlModel.addTriple(andreaInstRes, conoscePropRes, noemiInstRes);
		owlModel.addTriple(andreaInstRes, conoscePropRes, armandoInstRes);
		owlModel.addTriple(noemiInstRes, conoscePropRes, andreaInstRes);
		
		owlModel.addTriple(andreaInstRes, cognomePropRes, turbatiRes);
	}
	
	private TupleBindingsIterator executeQuery(OWLModel owlModel) throws UnsupportedQueryLanguageException, ModelAccessException, MalformedQueryException, QueryEvaluationException {
		
		String queryString = "SELECT ";
		queryString +="?person1 ?cognome1 ?person2  ?cognome2";
		queryString += "\nWHERE {";
		queryString += "\n\t?person1 <"+owlModel.getDefaultNamespace()+"conosceo>"+" ?person2 ."; 
		queryString += "\n\tOPTIONAL { ";
		queryString += "?person1 <"+owlModel.getDefaultNamespace()+"cognome> ?cognome1 . ";
		//queryString +="\n\t\t?person2 <"+owlModel.getDefaultNamespace()+"cognome> ?cognome2 . ";
		queryString += "}";
		
		
		queryString += "\n}";
		System.out.println("query:\n\t "+queryString); 
		
		Query query = owlModel.createQuery(queryString);
		TupleBindingsIterator tupleBindIter = ((TupleQuery) query).evaluate(false);
		
		return tupleBindIter;
	}
	
	private void printQueryResult(TupleBindingsIterator tupleBindIter) {
		System.out.println("printint SPARQL result:");
		while (tupleBindIter.hasNext()) {
			TupleBindings tupleBind = tupleBindIter.next();
			Set <String>bindNameSet = tupleBind.getBindingNames();
			System.out.println("\tTuple:");
			for(String bindingName : bindNameSet){
				ARTNode artNode = tupleBind.getBoundValue(bindingName);
				System.out.println("\t\t"+bindingName+" -> "+artNode);
			}
		}
	}
	
}
